/**
 * @author Pablo Pazos Gutierrez (pablo.swp@gmail.com)
 *
 */

import demographic.party.*
import demographic.identity.PersonName
import demographic.role.*
import hce.core.support.identification.UIDBasedID

import hce.HceService

import tablasMaestras.TipoIdentificador

import hce.core.composition.*

import com.thoughtworks.xstream.XStream

import converters.DateConverter

// TEST
import demographic.PixPdqDemographicAccess

// Para manejar eventos
import events.*


class DemographicController{

    def hceService
    def demographicService
    
    def index = {
       redirect(action:'admisionPaciente')
    }
    
    /**
     * Comienzo de la admision del paciente (proceso de identificacion
     * y seleccion del paciente).
     */
    def admisionPaciente = {
        // TODO: me deberia venir un id de episodio para el cual
        // quiero seleccionar un paciente.
        def tiposIds = TipoIdentificador.list()
        return [tiposIds: tiposIds]
    }
    
    /**
     * Busqueda de candidatos.
     */
    def findPatient = {
        
        println "PARAMS: " + params + "\n"
        

    //    def pixpdq = new PixPdqDemographicAccess()
        //pixpdq.findIdsById( new UIDBasedID(value:params.identificador) )
        //pixpdq.findPersonById( new UIDBasedID(value:params.identificador) )
        
        
        //def person = new Person()
        //person.properties = params
        //bindData(person, params, 'person')
        //println "Person: " + person
        
        
        //if (!params.identificador)
        /*
        if (!params.('person.ids[0].value'))
        {
            flash.message = "Identificador requerido"
            redirect(action:'admisionPaciente')
            return
        }
        */
        
        // TODO: aca va la consulta PIX al maciel.
        // Deberia hacerse como un strategy, definiendo una interfaz comun,
        // tanto para la entrada como para la salida.
        // Cual estrategia se elige, deberia sacarse de la config.
        // En la config dice que IMP se usa.
    
        
        def id = null
        if (params.identificador)
            id = new UIDBasedID(value:params.root+'::'+params.identificador)
            
        /*
        def candidatos1 = []
        if (params.identificador)
            candidatos1 = demographicService.findPersonById( new UIDBasedID(value:'::'+params.identificador) )
            
        println "CANDIDATOS 1: " + candidatos1
        */
        
        // Para la fecha no funciona el bindData, lo hago a mano
        def bd = null
        if (params.useBirthDate)
        {
            //String fecha = params.fechaNacimiento_day+'-'+params.fechaNacimiento_month+'-'+params.fechaNacimiento_year
            //java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy")
            //bd = sdf.parse(fecha)
            
            bd = DateConverter.dateFromParams( params, 'fechaNacimiento_' )
            //println "Date: " + bd
        }

        // TODO: si no hay datos para los nombres, no crear pn.
        def pn = null
        if (params.'personName.primerNombre'  || params.'personName.segundoNombre'||
            params.'personName.primerApellido' || params.'personName.segundoApellido')
        {
            pn = new PersonName()
            bindData(pn, params, 'personName')
            //println "Person Name: " + pn
        }
        
        /*
        // TODO: todavia no uso el sexo
        def candidatos2 = demographicService.findByPersonData(pn, bd, null)
        println "CANDIDATOS2 : " + candidatos2
        */
        
        println "======================================="
        println "busca por: "
        println "   PN: "+ pn
        println "   BD: "+ bd
        println "======================================="
        
        //findByPersonDataAndIdAndRole( PersonName n, Date bithdate, String sex, UIDBasedID id, String roleType )
        def candidatos = demographicService.findByPersonDataAndIdAndRole(
                pn,
                bd,
                null,
                id,
                Role.PACIENTE )
        
        // ==================================================================
        // TEST
        //pixpdq.findByPersonData(pn, bd, "M")
    //    def result = pixpdq.findByPersonData(pn, bd, null)
    //    XStream xstream = new XStream()
    //    println xstream.toXML(result) + "\n\n"
        // /TEST
        // ==================================================================
        
        
        // OJO! los candidatos de pix y pdq no tienen ID!!!!!
        // lo puse para hacer el OR entre cand 1 y cand 2
//        def candidatos = candidatos1.plus( candidatos2 ) //.unique{ it.id }
        

        render(view:'listaCandidatos', model:[candidatos:candidatos])
    }
    
    /**
     * Selecciona a un paciente en el sistema para ser atendido (identificacion positiva).
     */
    def seleccionarPaciente = {
        
        def persona = Person.get(params.id)
        
        
        // =====================================================================
        // 1) Si no hay un episodio seleccionado, muestro la patalla de show del
        // paciente que tiene un boton "crear episodio" para abrir un episodio
        // para ese paciente, es la apertura desde admision.
        
        // =====================================================================
        // 2) Si hay un episodio seleccionado, entonces admision o el medico esta
        // seleccionando un paciente para ese episodio. Es un paciente existente
        // o uno ingresado en el momento. Previo a asignar a esta persona al
        // episodio se debe verificar que no se tenga ya una persona seleccionada
        // (o simplemente pongo la que me digan y que ellos corrijan).
        // Cada correccion debe tener un log de quien lo hizo.
        // Vuelve a la pantalla principal del episodio seleccionado (show).

        
        if (!session.traumaContext?.episodioId) // caso 1)
        {
            println "No hay epidosio seleccionado"
            render( view:'show',
                    model: [
                            persona: persona,
                            root: persona.ids.toArray()[0].root,
                            extension: persona.ids.toArray()[0].extension // FIXME: la persona DEBE tener un ID y si tiene '/' p.e. en la cedula en lugar de - va a cagar la url, a no ser que se normalice.
                           ] )
        }
        else // caso 2)
        {
            println "Hay un episodio seleccionado"
            
            // Pide el episodio a la base para agregarle la participation del paciente
            def composition = Composition.get( session.traumaContext.episodioId )
            
            // PRE: el episodio no deberia tener un paciente asignado.
            if ( hceService.getPatientFromComposition( composition ) )
            {
                flash.message = 'trauma.show.feedback.patientAlreadySelectedForThisEpisode'
                redirect( controller:'trauma', action:'show',
                        params: [id: session.traumaContext.episodioId] )
                return
            }
            
            // Crea la participacion del paciente para la compostion del episodio
            def partySelf = hceService.createPatientPartysSelf(persona.ids.toArray()[0].root, persona.ids.toArray()[0].extension)
            def participation = hceService.createParticipationToPerformer( partySelf )
            
            composition.context.addToParticipations( participation )
            
            // Si no le pongo flush:true parece que demora un poco mas en guardar el partyself y
            // vuelve a la pagina rapido y muestra que el episodio no tiene paciente.
            if (!composition.save(flush:true))
            {
                println "ERROR compo: " + composition.errors
            }
            
            //println "ERROR participation: " + participation.errors
            //println "ERROR partySelf: " + partySelf.errors
            
            // FIXME: cuando selecciona un paciente y vuelve al show del episodio,
            //        no se ve el paciente, si se hace reload de la pagina, se ve el paciente...
            //        puede ser un tema de aca (hay que hacer flush de la session o algo),
            //        o es un tema de carga lazy en el trauma.show para las participations del
            //        episodio.
            
            redirect( controller:'trauma', action:'show',
                      params: [id: session.traumaContext.episodioId] )
        }
        
        // Mientras rederea aprovecho para lanzar el evento
        EventManager.getInstance().handle("paciente_seleccionado",
                [
                 patient: persona,
                 episodeId: session.traumaContext?.episodioId // puede ser null
                ]
        )
        
        //render('Selecciona paciente: ' + persona)
    }
    
    /**
     * Agrega un nuevo paciente cuando el paciente a atender no esta en el sistema.
     */
    def agregarPaciente = {
        println params
        if (params.doit)
        {
            /*
             * Account.withTransaction { status ->
                   def source = Account.get(params.from)
                   def dest = Account.get(params.to)
                   def amount = params.amount.toInteger()
                   if(source.active)
                   {
                     source.balance -= amount
                     if(dest.active) { dest.amount += amount }
                     else { status.setRollbackOnly() }
                 }
               }
             */
            
            //def id = new UIDBasedID(params)
            def id = UIDBasedID.create(params.root, params.extension) // TODO: if !hasExtension => error
            def name = new PersonName(params)
            
            def person = new Person( params ) // sexo, fechaNac    
            person.addToIds( id )
            person.addToIdentities( name )
            
            //person.fechaNacimiento = new Date(183, 11, 26)

            if (!person.save()) println person.errors
            
            def role = new Role(timeValidityFrom: new Date(), type: "paciente", performer: person)
            if (!role.save()) println role.errors
            
            redirect(action:'seleccionarPaciente', id:person.id)
            return
        }
        
        // creacion de un nuevo paciente
        def tiposIds = TipoIdentificador.list()
        return [tiposIds: tiposIds]
    }
}
